import json
import os
import sys
import uvicorn
import asyncio
from util.GitUtil import GitUtil
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
from vo.Response import Response
from vo.Config import Config
from vo.MyEncoder import MyEncoder
from util.GradleUtil import GradleUtil
from util.WebSocketUtil import Message
from datetime import datetime

root_path = os.getcwd()
sys.path.append(root_path)
app = FastAPI()
config = Config()
server_config = config.get_content("serverConfig")
gradle_util = GradleUtil()


# 存储所有活跃的WebSocket连接
class ConnectionManager:
    def __init__(self):
        self.active_connections: dict[str, WebSocket] = {}  # Store connections with UUIDs

    async def connect(self, websocket: WebSocket, uuid: str):
        self.active_connections[uuid] = websocket

    def disconnect(self, uuid: str):
        if uuid in self.active_connections:
            del self.active_connections[uuid]

    async def send_personal_message(self, message: str, uuid: str):
        if uuid in self.active_connections:
            await self.active_connections[uuid].send_text(message)

    async def broadcast(self, message: str):
        for connection in self.active_connections.values():
            await connection.send_text(message)


manager = ConnectionManager()


@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    try:
        # Receive the initial message containing the UUID
        await websocket.accept()
        try:
            data = await websocket.receive_text()
            # Assuming the data is a JSON string with a 'uuid' field
            credentials = json.loads(data)
            uuid = credentials.get('uuid')
            if not uuid:
                await websocket.close(code=1008)  # Close with policy violation code
                return
        except:
            await websocket.close(code=1004, reason="数据格式错误")  # Close with unsupported data code
            return

        await manager.connect(websocket, uuid)
        print(f"新的websocket客户端连接成功，UUID为{uuid}")
        await manager.send_personal_message(Message('status', 'success').to_json(), uuid)
        try:
            while True:
                data = await websocket.receive_text()
                print(f"收到消息: {data} 来自 {uuid}")
                # Process incoming messages as needed
        except WebSocketDisconnect:
            manager.disconnect(uuid)
            await manager.broadcast("Client disconnected")
    except json.JSONDecodeError:
        await websocket.close(code=1003)  # Close with unsupported data code


# 修改 gradle_util 相关方法，添加实时日志推送
async def send_gradle_log(message: str):
    current_time = datetime.now().strftime("[%H:%M:%S] ")
    await manager.broadcast(Message('normal', current_time + message).to_json())


def sync_send_gradle_log(message: str):
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    try:
        loop.run_until_complete(send_gradle_log(message))
    finally:
        loop.close()


# 修改回调函数的实现
def create_log_callback():
    def callback(message: str):
        try:
            loop = asyncio.get_running_loop()
        except RuntimeError:
            # 如果没有运行中的事件循环，使用同步方式发送日志
            sync_send_gradle_log(message)
        else:
            # 如果有运行中的事件循环，使用异步方式发送日志
            asyncio.create_task(send_gradle_log(message))

    return callback


# 设置 GradleUtil 的日志回调
gradle_util.set_log_callback(create_log_callback())

# 获取支持打包的产品
@app.get("/package/getProducts")
async def get_products():
    product_config = config.get_content("productConfig")
    return Response().successWithData(json.loads(product_config['products']))


# 获取支持打包的模块
@app.get("/package/getModules")
async def get_modules():
    module_config = config.get_content("moduleConfig")
    return Response().successWithData(json.loads(module_config['modules']))


@app.post("/package/packageApk")
async def package_apk(item: dict):
    # check是否正在打包中
    if not gradle_util.set_gradle_params(item):
        return Response().error('正在打包中，请稍后再试')
    await send_gradle_log(f"开始打包{item['implementationPre']},包含模块{item['modules'].split(',')}...")
    #  验证产品是否存在
    product_config = config.get_content("productConfig")
    products = json.loads(product_config['products'])
    if item['implementationPre'] not in [it['product'] for it in products]:
        return Response().error('要打包的产品不存在')
    # TODO 验证版本是否存在
    # 验证模块是否支持打包
    if item['modules'] != '':
        package_version_array = item['version'].split('.')
        package_version = int(package_version_array[len(package_version_array) - 1])
        module_config = config.get_content("moduleConfig")
        modules = json.loads(module_config['modules'])
        selected_modules = item['modules'].split(',')
        for module in selected_modules:
            if module not in [it['module'] for it in modules]:
                return Response().error(f'要打包的模块{module}不存在')
        for module in selected_modules:
            # 找到对应的模块配置
            config_a = next(it for it in modules if it['module'] == module)
            if package_version < int(config_a['minVersion']):
                return Response().error(
                    f"{module}模块最低支持的版本为{config_a['minVersion']},当前目标版本为{package_version}")

                # 重置仓库代码
    git_config = config.get_content("gitConfig")
    git_util = GitUtil(git_config['address'])
    await send_gradle_log("正在重置仓库代码...")
    if not git_util.discard_repo_changes():
        return Response().error('重置仓库代码失败')
    # 切换到dev分支
    if not git_util.checkout_branch('dev'):
        return Response().error('切换分支失败')
    # 拉取最新代码
    if not git_util.git_pull():
        return Response().error('拉取最新代码失败')
    # 切换到指定tag代码
    tag_config = config.get_content("tagConfig")
    if not git_util.checkout_tag(f"{tag_config['pre']}{item['version']}"):
        return Response().error('指定的打包版本不存在')

    gradle_util.start_gradle()
    await send_gradle_log("开始执行打包...")
    return Response().successWithData('true')


# 获取支持打包的版本
@app.get("/package/getTags")
async def get_tags_list():
    try:
        tag_config = config.get_content("tagConfig")
        git_config = config.get_content("gitConfig")
        git_util = GitUtil(git_config['address'])
        tags_list = [tag.replace(tag_config['pre'], '') for tag in git_util.get_tags_list() if
                     tag.startswith(tag_config['pre'])]
        return Response().successWithData(tags_list)
    except Exception as e:
        return Response().error(str(e))


def toJson(obj):
    return json.dumps(obj, cls=MyEncoder)


if __name__ == "__main__":
    app.add_middleware(CORSMiddleware,
                       allow_origins=["*"],
                       allow_credentials=True,
                       allow_methods=["*"],
                       allow_headers=["*"], )
    uvicorn.run(app, host='0.0.0.0', port=server_config['port'], reload=False)
